/**
 * 
 */
package archsw0904.controller.shopping.cart;

import java.math.BigDecimal;
import java.util.GregorianCalendar;
import java.util.Map;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import archsw0904.controller.shopping.common.BookListVisualizationInfo;
import archsw0904.controller.shopping.common.CartException;
import archsw0904.model.Book;
import archsw0904.model.Cart;
import archsw0904.model.OrderedCopies;
import archsw0904.model.ProfileClient;


/**
 * @author ASGroup0904
 * 
 */

@Stateless
@WebService
public class CartBean implements CartBeanLocal{

	@PersistenceContext
	private EntityManager em;
	
	public Integer createCart( Integer idClient )  throws CartException {

		ProfileClient pc ;
		Cart cart ;
		Query q ;
		q= em.createQuery("SELECT OBJECT(obj) FROM ProfileClient obj WHERE obj.id = " + idClient.toString() ); 
		if ( q == null ) {
			throw new CartException ( ExceptionType.ClientError ) ;
		} else {
			try {
				pc = (ProfileClient) q.getSingleResult() ;
				if ( !pc.getId().equals(idClient) ) throw new CartException ( ExceptionType.ClientError ) ;
			} catch (NoResultException e) {
				throw new CartException ( ExceptionType.ClientError ) ;
				}
		}
		q = em.createQuery("SELECT OBJECT(obj) FROM Cart obj WHERE obj.client = " + idClient.toString() );
		if ( q != null ) {
			if ( !q.getResultList().isEmpty() ) {
				cart = (Cart) q.getSingleResult() ;
				if ( cart == null ) throw new CartException ( ExceptionType.CartError ) ;
				if ( cart.getClient().getId().equals(idClient) ) throw new CartException ( ExceptionType.CartPresent ) ;
			}
		}
		cart = new Cart();
		cart.setDate(null);
		cart.setClient(pc);
		em.persist(cart);
		
		return cart.getCartId();

	}

	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public Boolean addBook(Integer clientId, Integer bookId) throws CartException {

		// carrello esistente
		Cart cart = getCart(clientId);
		if ( cart == null ) {
			throw new CartException ( ExceptionType.CartNotPresent ) ;
		}
		
		//libro esistente
		Query q = em.createQuery("SELECT OBJECT(obj) FROM Book obj WHERE obj.id = " + bookId.toString());
		Book book = (Book) q.getSingleResult();
		if ( book == null ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		//libro gia nel carrello
		Map<Book,OrderedCopies> list = cart.getCartLines() ;
		if ( list.isEmpty() ) cart.setDate(new GregorianCalendar().getTime()) ;
		else {
			if ( list.containsKey(book) ) {
				throw new CartException ( ExceptionType.BookPresent ) ;
			}
		}
		
		//disponibilita' di una copia
		if ( book.getAvailableCopies().intValue() >= 1 ) {
			book.decAvailableCopies(1) ;
		} else {
			throw new CartException ( ExceptionType.CopyNotPresent ) ;
		}
		
		OrderedCopies oCopies = new OrderedCopies( 1 );
		
		em.persist(oCopies) ;

		cart.getCartLines().put(book, oCopies);
		BigDecimal price = book.getPrice() ;
		price =price.add(cart.getTotal()) ;
		cart.setTotal(price) ;
		em.persist(cart);

		return true ;

	}

	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public Boolean removeBook (Integer clientId, Integer bookId) throws CartException {
		
		// carrello esistente
		Cart cart = getCart(clientId);
		if ( cart == null ) {
			throw new CartException ( ExceptionType.CartNotPresent ) ;
		}
		
		//libro esistente
		Query q = em.createQuery("SELECT OBJECT(obj) FROM Book obj WHERE obj.id = " + bookId.toString());
		Book book = (Book) q.getSingleResult();
		if ( book == null ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		//libro presente nel carrello
		if ( !cart.getCartLines().containsKey(book) ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		// correttezza del numero di copie rilasciate
		OrderedCopies copies = cart.getCartLines().get(book) ;
		// magazzino
		if ( book.getCopiesInStockroom().intValue() < (book.getAvailableCopies().intValue() + copies.getNumberOfCopies().intValue()) ) 
			throw new CartException ( ExceptionType.TooManyCopies ) ;
				
		// aggiornamento copie nel libro
		book.addAvailableCopies(copies.getNumberOfCopies()) ;
		em.persist(book) ;
		
		// rimozione dal carrello
		OrderedCopies remCopies = cart.getCartLines().remove(book) ;
		em.remove(remCopies);
		
		if (cart.getCartLines().isEmpty()) cart.setDate(null) ;
		BigDecimal price = book.getPrice() ;
		price =price.multiply(new BigDecimal(copies.getNumberOfCopies().intValue())) ;
		BigDecimal sPrice = cart.getTotal() ;
		sPrice = sPrice.subtract(price) ;
		cart.setTotal(sPrice) ;
		em.persist(cart) ;
		
		return true;
		
	}
	
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public Integer addCopies (Integer clientId, Integer bookId, Integer nCopies) throws CartException {
		
		if ( nCopies.intValue() <= 0) throw new CartException(ExceptionType.CopiesLT0) ;

		// carrello esistente
		Cart cart = getCart(clientId);
		if ( cart == null ) {
			throw new CartException ( ExceptionType.CartNotPresent ) ;
		}
				
		//libro esistente
		Query q = em.createQuery("SELECT OBJECT(obj) FROM Book obj WHERE obj.id = " + bookId.toString());
		Book book = (Book) q.getSingleResult();
		if ( book == null ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		//libro presente nel carrello
		if ( !cart.getCartLines().containsKey(book) ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		//disponibilita' delle copie
		OrderedCopies copies = cart.getCartLines().get(book) ;
		if ( book.getAvailableCopies().intValue() >= nCopies ) {
				book.decAvailableCopies(nCopies) ;
		} else {
			return new Integer (book.getAvailableCopies().intValue()) ;
		}
		
		em.persist(book) ;
		
		copies.setNumberOfCopies(copies.getNumberOfCopies() + nCopies);
		
		em.persist(copies) ;
		
		BigDecimal price = book.getPrice() ;
		price = price.multiply(new BigDecimal(nCopies.intValue()));
		price = price.add(cart.getTotal()) ;
		cart.setTotal(price) ;
		em.persist(cart) ;
		
		return new Integer(copies.getNumberOfCopies()) ;
		
	}
	
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public Boolean removeCopies (Integer clientId, Integer bookId, Integer nCopies) throws CartException {
		
		if ( nCopies.intValue() <= 0) throw new CartException(ExceptionType.CopiesLT0) ;
		
		// carrello esistente
		Cart cart = getCart(clientId);
		if ( cart == null ) {
			throw new CartException ( ExceptionType.CartNotPresent ) ;
		}
		
		//libro esistente
		Query q = em.createQuery("SELECT OBJECT(obj) FROM Book obj WHERE obj.id = " + bookId.toString());
		Book book = (Book) q.getSingleResult();
		if ( book == null ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		//libro presente nel carrello
		if ( !cart.getCartLines().containsKey(book) ) {
			throw new CartException ( ExceptionType.BookNotPresent ) ;
		}
		
		// correttezza del numero di copie rilasciate
		// magazzino
		if ( book.getCopiesInStockroom().intValue() < (nCopies.intValue() + book.getAvailableCopies().intValue()) ) return false ;
		// ordine
		OrderedCopies copies = cart.getCartLines().get(book) ;
		if ( copies.getNumberOfCopies().intValue() < nCopies.intValue() ) return false ;
		
		
		// aggiornamento copie nel libro
		book.addAvailableCopies(nCopies) ;
		em.persist(book) ;
		if ( ( copies.getNumberOfCopies().intValue() - nCopies.intValue()) == 0 ) {
			// rimozione dal carrello
			OrderedCopies remCopies = cart.getCartLines().remove(book) ;
			em.remove(remCopies);
			if (cart.getCartLines().isEmpty()) cart.setDate(null) ;
			
		} else {
			// decremento
			copies.setNumberOfCopies(copies.getNumberOfCopies() - nCopies);
			em.persist(copies) ;
		}		
		
		BigDecimal price = book.getPrice() ;
		price = price.multiply(new BigDecimal(nCopies.intValue())) ;
		BigDecimal sPrice = cart.getTotal() ;
		sPrice = sPrice.subtract(price) ;
		cart.setTotal(sPrice) ;
		
		em.persist(cart) ;
		
		return true;
		
	}
	
	// id libro, titolo, prezzo unitario, isbn, tot carrello,
	public BookListVisualizationInfo getBookList ( Integer clientId ) throws CartException {
		
		// carrello esistente
		Cart cart = getCart(clientId);
		if ( cart == null ) {
			throw new CartException ( ExceptionType.CartNotPresent ) ;
		}
		
		BookListVisualizationInfo cInfo = new BookListVisualizationInfo () ;
		cInfo.setTotalPrice(cart.getTotal()) ;
		
		Map<Book,OrderedCopies> mapList = cart.getCartLines() ;
		
		for ( Book book : mapList.keySet() ) {
			cInfo.addBook(book, mapList.get(book).getNumberOfCopies() ) ;
		}
		
		return cInfo;
		
	}
	
	private Cart getCart(Integer idClient) throws CartException{
		ProfileClient pc ;
		Cart cart = null;
		Query q ;
		q= em.createQuery("SELECT OBJECT(obj) FROM ProfileClient obj WHERE obj.id = " + idClient.toString() );
		if ( q == null ) {
			throw new CartException ( ExceptionType.ClientError ) ;
		} else {
			try {
				pc = (ProfileClient) q.getSingleResult() ;
				if ( !pc.getId().equals(idClient) ) throw new CartException ( ExceptionType.ClientError ) ;
			} catch (NoResultException e) {
				throw new CartException ( ExceptionType.ClientError ) ;
				}
		}
		q = em.createQuery("SELECT OBJECT(obj) FROM Cart obj WHERE obj.client = " + idClient.toString() );
		if ( q != null ) {
			if ( !q.getResultList().isEmpty() ) {
				cart = (Cart) q.getSingleResult() ;
				if ( cart == null ) throw new CartException ( ExceptionType.CartError ) ;
			}
		}
		return cart;
	}
}
